﻿/* 使用说明
 * version 2.0;
 * author: Liao JP; e-mail:ljpzsu@126.com
 * date:5/12/2012
 * 
 * Render类：包含一个各种渲染方法，部分可重载成带符号参数的新方法
 * TMapColor类：专题图渲染时可能用到的关于颜色（带）设置的有用方法
 */
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;

namespace popGis
{
    class Render
    {
        # region 对图层进行渲染
        /// <summary>
        /// 改变图层底色的简单渲染
        /// </summary>
        /// <param name="pLayer"></param>
        static public void SimpleRender(ILayer pLayer)
        {
            //检查是否为面状图层
            IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
            IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
            if (pFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon) return;//检查是否为面状图层

            //获取颜色对象            
            IRgbColor pRGBColor = new RgbColorClass();
            Random ran = new Random(System.DateTime.Now.Second);
            int iUp = 128; int iDown = 0;
            pRGBColor.Red = ran.Next(iDown, iUp);
            pRGBColor.Green = ran.Next(iDown, iUp);
            pRGBColor.Blue = ran.Next(iDown, iUp);

            //创建简单填充符号——所有渲染公有的步骤
                //防止不同渲染接口因类型不匹配而出错
            ISimpleFillSymbol pSym = new SimpleFillSymbolClass();
            pSym.Color = pRGBColor as IColor;

            //创建渲染方式，赋以上面符号属性
            ISimpleRenderer pSimpleRender = new SimpleRendererClass();
            pSimpleRender.Symbol = pSym as ISymbol;

            //获得图层渲染功能的接口
            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;

            //进行渲染
            pGeoFeatureLayer.Renderer = pSimpleRender as IFeatureRenderer;
        }

        /// <summary>
        /// 简单线状(----)填充渲染
        /// </summary>
        /// <param name="axMapControl"></param>
        static public void LineFillRender(ILayer pLayer)
        {
            //检查是否为面状图层
            IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
            IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
            if (pFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon) return;//检查是否为面状图层

            IRgbColor pRgbColor = new RgbColorClass();
            pRgbColor.Red = 60; pRgbColor.Green = 120; pRgbColor.Blue = 45;
            //设置线状填充符号
            ILineSymbol pLineSymbol = new SimpleLineSymbolClass();
            pLineSymbol.Color = pRgbColor as IColor;
            pLineSymbol.Width = 0.8;

            ISimpleFillSymbol pSimpleFillSymbol = new SimpleFillSymbolClass();
            pSimpleFillSymbol.Outline = pLineSymbol;
            pSimpleFillSymbol.Style = esriSimpleFillStyle.esriSFSHorizontal;

            ISimpleRenderer pSimpleRenderer = new SimpleRendererClass();
            pSimpleRenderer.Symbol = pSimpleFillSymbol as ISymbol;

            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;
            pGeoFeatureLayer.Renderer = pSimpleRenderer as IFeatureRenderer;
        }

        /// <summary>
        /// 唯一值渲染
        /// </summary>
        /// <param name="pLayer">待渲染图层</param>
        /// <param name="FieldName">按何字段来设置颜色</param>
        static public void UniqueValueRender(ILayer pLayer, string FieldName)
        {
            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;

            //检查是否为面状图层
            IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
            IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
            if (pFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon) return;//检查是否为面状图层


            // 产生一个随机的色带
            IEnumColors pEnumRamp = TMapColor.CreateRandomColorRamp(50).Colors;
            IColor pNextUniqueColor = null;

            IUniqueValueRenderer pUniqueValueRender = new UniqueValueRendererClass();
            pUniqueValueRender.FieldCount = 1;//使用0一个属性
            pUniqueValueRender.set_Field(0, FieldName);//用于渲染的第一个属性（Index=0）

            //ITable pTable = pLayer as ITable;//获得属性表
            IDisplayTable dispTable = ((IDisplayTable)pFeatureLayer);

            ITable pTable = dispTable.DisplayTable;
            int fldIndex = pTable.Fields.FindField(FieldName);

            IQueryFilter pQueryFilter = new QueryFilterClass();
            pQueryFilter.AddField(FieldName);//属性过滤，得到单一属性的内容（表），类似于SQL的Select语句

            ICursor pCursor = dispTable.SearchDisplayTable(pQueryFilter, true);
            IRow pRow = pCursor.NextRow();
            while (pRow != null)
            {
                IRowBuffer pRowBuffer = pRow as IRowBuffer;
                System.Object cValue = pRowBuffer.get_Value(fldIndex);

                pNextUniqueColor = pEnumRamp.Next();
                if (pNextUniqueColor == null)
                {
                    pEnumRamp.Reset();
                    pNextUniqueColor = pEnumRamp.Next();
                }

                ISimpleFillSymbol pSym = new SimpleFillSymbolClass();
                pSym.Color = pNextUniqueColor;

                pUniqueValueRender.AddValue(cValue.ToString(), "", pSym as ISymbol);
                pRow = pCursor.NextRow();
            }

            pGeoFeatureLayer.Renderer = pUniqueValueRender as IFeatureRenderer;

            System.Runtime.InteropServices.Marshal.ReleaseComObject(pCursor);
            GC.Collect();//使用游标时记得清除，以免大量使用后造成垃圾堆积，使程序无法运行
            GC.WaitForPendingFinalizers();

        }

        /// <summary>
        /// 按字段分级设色渲染
        /// </summary>
        /// <param name="pLayer">待渲染图层</param>
        /// <param name="FieldName">按何数值字段来设置颜色</param>
        /// <param name="classCount">分级数量</param>
        static public void ClassBreakRender(ILayer pLayer, string FieldName, int classCount)
        {
            IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
            IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
            if (pFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon) return;

            ITable dispTable = ((IDisplayTable)pFeatureLayer).DisplayTable;

            ITableHistogram pTableHistogram;
            IBasicHistogram pBasicHistogram;

            pTableHistogram = new BasicTableHistogramClass();
            //按照 数值字段分级(??是否要捕捉错误)
            pTableHistogram.Table = ((IDisplayTable)pLayer).DisplayTable;
            pTableHistogram.Field = FieldName;
            pBasicHistogram = pTableHistogram as IBasicHistogram;

            object values;
            object frequencys;

            //先统计每个值和各个值出现的次数
            pBasicHistogram.GetHistogram(out values, out frequencys);

            //创建等间距分级对象
            IClassifyGEN classifyGEN = new EqualIntervalClass();
            //用统计结果进行分级 ，级别数目为classCount
            classifyGEN.Classify(values, frequencys, ref classCount);
            //获得分级结果,是个 双精度类型数组 
            double[] classes;
            classes = classifyGEN.ClassBreaks as double[];

            IEnumColors enumColors = TMapColor.CreateAlgorithmicColorRamp(classes.Length).Colors;
            IColor pColor;

            IClassBreaksRenderer pClassBreaksRenderer = new ClassBreaksRendererClass();
            pClassBreaksRenderer.Field = FieldName;
            pClassBreaksRenderer.BreakCount = classCount;
            pClassBreaksRenderer.SortClassesAscending = true;

            ISimpleFillSymbol simpleFillSymbol;
            for (int i = 0; i < classes.Length - 1; i++)
            {
                pColor = enumColors.Next();
                simpleFillSymbol = new SimpleFillSymbolClass();
                simpleFillSymbol.Color = pColor;
                simpleFillSymbol.Style = esriSimpleFillStyle.esriSFSSolid;

                pClassBreaksRenderer.set_Symbol(i, simpleFillSymbol as ISymbol);
                pClassBreaksRenderer.set_Break(i, classes[i + 1]);
            }

            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;
            pGeoFeatureLayer.Renderer = pClassBreaksRenderer as IFeatureRenderer;
        }

        /// <summary>
        /// 点密度专题渲染
        /// </summary>
        /// <param name="pLayer">待渲染图层</param>
        /// <param name="FieldName">按何字段来设置颜色</param>
        static public void DotDensityRender(ILayer pLayer, string FieldName)
        {
            IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
            IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
            if (pFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon) return;

            // 建立一个用于填充的点符号
            IDotDensityFillSymbol pDotDensityFillSymbol = new DotDensityFillSymbolClass();
            pDotDensityFillSymbol.DotSize = 3;
            pDotDensityFillSymbol.Color = TMapColor.getRGB(0, 0, 0);
            pDotDensityFillSymbol.BackgroundColor = TMapColor.getRGB(239, 228, 190);

            ITable pTable = pLayer as ITable;
            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;

            IDotDensityRenderer pDotDensityRender = new DotDensityRendererClass();
            IRendererFields pRendererFields = pDotDensityRender as IRendererFields;
            pRendererFields.AddField(FieldName);

            ISymbolArray pSymbolArray = pDotDensityFillSymbol as ISymbolArray;
            ISimpleMarkerSymbol pMarkerSymbol = new SimpleMarkerSymbolClass();
            pMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSDiamond;

            pMarkerSymbol.Color = TMapColor.getRGB(0, 0, 0);
            pSymbolArray.AddSymbol(pMarkerSymbol as ISymbol);

            // 开始着色
            pDotDensityRender.DotDensitySymbol = pDotDensityFillSymbol;
            pDotDensityRender.DotValue = 2;
            pGeoFeatureLayer.Renderer = pDotDensityRender as IFeatureRenderer;
        }


        # endregion
    }

    class TMapColor
    {
        # region 设计颜色对象

        /// <summary>
        /// 获取颜色对象
        /// </summary>
        /// <param name="r">Red</param>
        /// <param name="g">Green</param>
        /// <param name="b">Blue</param>
        /// <param name="t">Transparency</param>
        /// <returns>控制RGB颜色、透明度</returns>
        public static IRgbColor getRGB(int r, int g, int b,int t)
        {
            IRgbColor pColor;
            pColor = new RgbColorClass();
            pColor.Red = r;pColor.Green = g;
            pColor.Blue = b;pColor.Transparency = (byte)t;
            return pColor;
        }
        public static IRgbColor getRGB(int r, int g, int b)
        {
            IRgbColor pColor;
            pColor = new RgbColorClass();
            pColor.Red = r;
            pColor.Green = g;
            pColor.Blue = b;
            return pColor;
        }
        public static IRgbColor getRGB()
        {
            IRgbColor pColor = getRGB(255,255,255);
            return pColor;
        }

        # endregion

        # region 设计颜色显示

        /// <summary>
        /// 创建颜色带
        /// </summary>
        /// <param name="count">颜色带颜色数目</param>
        /// <returns>IColorRamp</returns>
        public static IColorRamp CreateAlgorithmicColorRamp(int count)
        {
            if (count <= 0) return null;

            IAlgorithmicColorRamp algColorRamp = new AlgorithmicColorRampClass();

            //设置AlgorithmicColorRampClass的起止颜色属性
            algColorRamp.ToColor = getRGB(255, 0, 0);
            algColorRamp.FromColor = getRGB(0, 0, 255);
            //设置梯度类型
            algColorRamp.Algorithm = esriColorRampAlgorithm.esriCIELabAlgorithm;
            //设置颜色带颜色数量
            algColorRamp.Size = count;
            //创建颜色带
            bool bture = true;
            algColorRamp.CreateRamp(out bture);

            return algColorRamp;
        }

        /// <summary>
        /// 产生一个随机的色带
        /// </summary>
        /// <param name="count">色彩数目</param>
        /// <returns>IColorRamp</returns>
        public static IColorRamp CreateRandomColorRamp(int count)
        {
            IRandomColorRamp pColorRamp = new RandomColorRampClass();

            pColorRamp.StartHue = 76;
            pColorRamp.MinValue = 85;
            pColorRamp.MinSaturation = 20;
            pColorRamp.EndHue = 188;
            pColorRamp.MaxValue = 100;
            pColorRamp.MaxSaturation = 40;

            pColorRamp.Size = count;

            bool bOK = false;
            pColorRamp.CreateRamp(out bOK);
            return pColorRamp;
        }

        # endregion
    }

    class AOUtil
    {
        # region 获得几何要素IGeometry
        /// <summary>
        /// 返回被选择的第一个几何元素
        /// </summary>
        public static IGeometry GetSelectGeometry(AxMapControl axMapControl)
        {

            for (int i = 0; i < axMapControl.LayerCount; i++)
            {
                IFeatureLayer pFeatureLayer = axMapControl.get_Layer(i) as IFeatureLayer;
                IFeatureSelection pFeatureSelection = pFeatureLayer as IFeatureSelection;
                ISelectionSet pSelectionSet = pFeatureSelection.SelectionSet;

                ICursor pCursor = null;
                pSelectionSet.Search(null, false, out pCursor);
                IFeatureCursor pFeatureCursor = pCursor as IFeatureCursor;
                IFeature pFeature = pFeatureCursor.NextFeature();

                System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureCursor);
                GC.Collect();
                GC.WaitForPendingFinalizers();

                if (pFeature != null) return pFeature.Shape;
            }

            return null;
        }

        /// <summary>
        /// 获得外包型缓冲区
        /// </summary>
        /// <param name="pGeometry">要建立缓冲区的几何要素</param>
        /// <param name="bufferDis">缓冲区半径(km)</param>
        /// <returns>外包型缓冲区要素</returns>
        public static IGeometry CreateOutFillBuffer(IGeometry pGeometry, double bufferDis)
        {
            if (pGeometry == null || bufferDis <= 0) return null;

            ITopologicalOperator pTopologicalOperator = pGeometry as ITopologicalOperator;
            IGeometry pBufferGeometry = pTopologicalOperator.Buffer(bufferDis);

            return pBufferGeometry;
        }

        # endregion

        # region 获得图层ILayer

        /// <summary>
        /// 从名字获取层
        /// </summary>
        /// <param name="name">图层名字</param>
        /// <returns>ILayer接口</returns>
        public static ILayer GetLayerByName(AxMapControl axMapControl, String name)
        {
            for (int i = 0; i < axMapControl.LayerCount; i++)
            {
                ILayer pLayer = axMapControl.get_Layer(i);
                if (pLayer.Name == name) return pLayer;
            }

            return null;
        }

        # endregion
    }
}
